/*
 * @Description: 4个核心的实现
 * @Version: @1.0.0
 * @Autor: YJY
 * @Date: 2021-07-19 17:19:48
 * @LastEditors: YJY
 * @LastEditTime: 2021-07-20 15:16:24
 */
import { foreachV } from './utils'
let Vue
export class Store { // 容器
  constructor (options) {
    // console.log(options)
    // 实现getters.名称  将{属性：fn} 变成{属性：值} 但没有缓存机制
    const computed = {}
    const getters = options.getters
    this.getters = {}
    foreachV(getters, (key, fn) => {
      computed[key] = () => {
        return fn(this.state)
      }
      Object.defineProperty(this.getters, key, {
        get: () => {
          return this.vm[key]
        }
      })
    })
    // Object.keys(getters).forEach(key => {
    //   Object.defineProperty(this.getters, key, {
    //     get: () => {
    //       return getters[key](this.state)
    //     }
    //   })
    // })
    // this.state = options.state // 实现state的功能 但是没有响应式
    // 实现缓存机制 利用 computed
    this.vm = new Vue({
      data: {
        state: options.state
      },
      computed
    })
    // action 和 mutations
    const mutations = options.mutations
    this.mutations = {}
    foreachV(mutations, (key, fn) => {
      this.mutations[key] = (data) => {
        fn(this.state, data)
      }
    })
    const actions = options.actions
    this.actions = {}
    foreachV(actions, (key, fn) => {
      this.actions[key] = (data) => {
        console.log(this)
        fn(this, data)
      }
    })
  }

  commit = (name, data) => {
    // 触发的方法 mutations
    this.mutations[name](data)
  }

  dispatch = (name, data) => {
    // 触发的方法 dispatch
    this.actions[name](data)
  }

  // 添加属性监听 实现响应式 当然也可以用 Object.proptroy
  get state () {
    return this.vm.state
  }
}

// 给Vue所有使用的实例添加一个属性  $store
export const install = function (_Vue) { // 插件开发 _Vue 这里引入Vue有两个作用 1.可以使用Vue中的方法 2.和外面的Vue的版本是一样的
  Vue = _Vue
  // console.log(Vue) Vue的构造函数
  Vue.mixin({ // 混入全局的数据和方法
    beforeCreate () { // Vue 组件渲染的关系 父子关系 根实例  组件根实例 当前组件实例
      // console.log(this.$options.name)
      const options = this.$options
      if (options.store) { // 有 store 说明是根实例 在main中挂载了store
        this.$store = options.store
      } else { // 判断是否拥有父实例
        this.$store = this.$parent && this.$parent.$store
      }
    }
  })
}
